package com.zmn.oms.business.impl.order;

import com.alibaba.fastjson.JSON;
import com.google.common.collect.Lists;
import com.zmn.base.oms.common.model.es.orderwork.EsOrderWork;
import com.zmn.base.product.common.consts.BaseProductConsts;
import com.zmn.base.product.common.consts.DubboConsts;
import com.zmn.base.product.common.dto.categ.CategProductGroupDRO;
import com.zmn.base.product.common.dto.product.ProductBaseQuery;
import com.zmn.base.product.common.dto.product.ec.DefaultEcProductQuery;
import com.zmn.base.product.common.dto.product.ec.ProductBaseDRO;
import com.zmn.base.product.common.query.categ.CategProductGroupQuery;
import com.zmn.base.product.dubbo.interfaces.categ.serv.CategServProductListRemoteService;
import com.zmn.base.product.dubbo.interfaces.product.foreign.ProductForeignListRemoteService;
import com.zmn.common.dto2.ResponseDTO;
import com.zmn.common.utils.collection.CollectionUtil;
import com.zmn.common.utils.date.DateUtil;
import com.zmn.common.utils.number.NumberUtil;
import com.zmn.common.utils.reflect.BeanMapper;
import com.zmn.common.utils.string.StringUtil;
import com.zmn.consts.GlobalConsts;
import com.zmn.manager.mq.constant.MqTopicConsts;
import com.zmn.manager.mq.interfaces.ZmnMQSender;
import com.zmn.oms.business.interfaces.es.OrderWorkEsBService;
import com.zmn.oms.business.interfaces.order.DuplicateOrderBService;
import com.zmn.oms.common.constant.CompanyConsts;
import com.zmn.oms.common.constant.OrderConsts;
import com.zmn.oms.common.constant.OrderStatusConsts;
import com.zmn.oms.common.dio.redistribute.DoingDuplicateOrderDIO;
import com.zmn.oms.common.dto.ResultDTO;
import com.zmn.oms.manager.utils.OmsMqTagConsts;
import com.zmn.oms.model.dto.order.zmn.ZsNormalUpdateOrderDTO;
import com.zmn.oms.model.dto.product.OrderProductDTO;
import com.zmn.oms.model.dto.work.modify.CancelDuplicateOrderDTO;
import com.zmn.oms.model.dto.work.modify.DuplicateOrderDTO;
import com.zmn.oms.model.dto.work.modify.SuspectedDuplicateOrderDTO;
import com.zmn.oms.model.dto.work.modify.VerifyTelephoneOrProductDTO;
import com.zmn.oms.model.entity.detail.OrderDetail;
import com.zmn.oms.model.entity.work.OrderWork;
import com.zmn.oms.services.interfaces.detail.OrderDetailService;
import com.zmn.oms.services.interfaces.orderencrypt.OrderEncryptService;
import com.zmn.oms.services.interfaces.work.OrderWorkService;
import com.zmn.track.common.constant.TrackConfigConsts;
import com.zmn.track.common.constant.TrackConsts;
import com.zmn.track.dubbo.dto.CompleteTrackDIO;
import com.zmn.track.dubbo.dto.TrackWorkDIO;
import com.zmn.track.dubbo.dto.TrackWorkDRO;
import com.zmn.track.dubbo.dto.TrackWorkQuery;
import com.zmn.track.dubbo.interfaces.trackwork.TrackWorkListRemoteService;
import com.zmn.track.dubbo.interfaces.trackwork.TrackWorkModifyRemoteService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.dubbo.config.annotation.DubboReference;
import org.elasticsearch.common.unit.DistanceUnit;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.data.elasticsearch.core.query.FetchSourceFilter;
import org.springframework.data.elasticsearch.core.query.NativeSearchQuery;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;

import javax.annotation.Resource;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.Optional;

/**
 * 类描述：重复订单
 *
 * @author liuying
 * @date 2018/11/07 19:31
 */
@Service
@Slf4j
public class DuplicateOrderBServiceImpl implements DuplicateOrderBService {

    @Autowired
    private OrderWorkService orderWorkService;
    @Autowired
    private OrderDetailService orderDetailService;
    @Autowired
    private OrderWorkEsBService orderWorkEsBService;
    @Resource
    ZmnMQSender zmnMQSender;
    @Resource
    private OrderEncryptService orderEncryptService;

    @DubboReference(version = DubboConsts.INTERFACE_VERSION, check = false)
    private ProductForeignListRemoteService productForeignListRemoteService;

    @DubboReference(version = DubboConsts.INTERFACE_VERSION, check = false)
    private CategServProductListRemoteService categServProductListRemoteService;

    @DubboReference(version = com.zmn.track.dubbo.consts.DubboConsts.INTERFACE_VERSION, check = false)
    private TrackWorkListRemoteService trackWorkListRemoteService;
    @DubboReference(version = com.zmn.track.dubbo.consts.DubboConsts.INTERFACE_VERSION, check = false)
    private TrackWorkModifyRemoteService trackWorkModifyRemoteService;

    // 房屋业务产品组 = C-防水补漏组/1000 || C-墙面组/1003 || C-瓷砖地板组/1005 || C-厨卫改造组/1031 || F-厨卫翻新/1032 || F-防水补漏组/1001 || F-墙面刷新组/1004
    private final List<Integer> houseServProductGroupIdList = Lists.newArrayList(1000, 1003, 1005, 1031, 1032, 1001, 1004);


    // 1、家电：服务分类  = 1002、1003、1011
    // 2、清洗：服务分类 = 1001
    // 3、家具：服务分类 = 1004、1005、1006、1007、1009、1012 、1020、1022
    // 4、房屋修缮：服务分类ID = 1008、1021、1023、1024
    private final List<Integer> householdServCategIdList = Lists.newArrayList(1002, 1003, 1011);
    private final List<Integer> cleanServCategIdList = Lists.newArrayList(1001);
    private final List<Integer> furnitureServCategIdList = Lists.newArrayList(1004, 1005,1006, 1007, 1009, 1012 , 1020, 1022);
    private final List<Integer> houserepairServCategIdList = Lists.newArrayList(1008, 1021, 1023, 1024);

    /**
     * 下单重复工单判断 (只判断新单)
     * a、同一下单平台&相同业务类型，所有：未完成-进行中工单
     * b、电话01、02、03有其中1个电话相同
     * c、前台产品相同
     * d、不包括：预付款待支付的工单
     *
     * @param duplicateDTO
     * @return
     */
    @Override
    public Long findDuplicateOrderId(DuplicateOrderDTO duplicateDTO) {
        ProductBaseDRO product = null;
        if (Objects.equals(duplicateDTO.getProductShowType(), BaseProductConsts.EC_SHOW_TYPE)) {
            // 传过来就是前台产品
            ProductBaseQuery productBaseQuery = new ProductBaseQuery();
            productBaseQuery.setProductId(duplicateDTO.getProductId());
            productBaseQuery.setShowType(duplicateDTO.getProductShowType());
            ResponseDTO<List<ProductBaseDRO>> productResponseDTO = productForeignListRemoteService.listBaseDROByQuery(productBaseQuery);
            if (!productResponseDTO.isSuccess() || CollectionUtil.isNullOrEmpty(productResponseDTO.getData())) {
                return null;
            }
            product = productResponseDTO.getData().get(0);
        } else {
            // 后端产品找前端产品
            DefaultEcProductQuery defaultEcProductQuery = new DefaultEcProductQuery();
            defaultEcProductQuery.setProductIdList(Lists.newArrayList(duplicateDTO.getProductId()));
            defaultEcProductQuery.setShowType(BaseProductConsts.EC_SHOW_TYPE);
            com.zmn.common.dto2.ResponseDTO<List<ProductBaseDRO>> showProductRemote = productForeignListRemoteService.listEcErpProductByQuery(defaultEcProductQuery);
            if (!showProductRemote.isSuccess() || CollectionUtil.isNullOrEmpty(showProductRemote.getData())) {
                return null;
            }
            product = showProductRemote.getData().get(0);
        }

        // 产品信息
        CancelDuplicateOrderDTO duplicateOrderDTO = BeanMapper.map(duplicateDTO, CancelDuplicateOrderDTO.class);
        duplicateOrderDTO.setType(OrderConsts.ORDER_TYPE_NEW);
        duplicateOrderDTO.setBizType(duplicateOrderDTO.getBizType());
        duplicateOrderDTO.setServProductGroupId(duplicateOrderDTO.getServProductGroupId());
        duplicateOrderDTO.setServCategId(product.getServCategId());
        duplicateOrderDTO.setShowCategId(product.getCategId());
        duplicateOrderDTO.setPlatWork(duplicateDTO.getPlat());
        duplicateOrderDTO.setReceiveTime(DateUtil.getNow());
        duplicateOrderDTO.setExcludeOrderId(duplicateDTO.getOrderId());

        if (log.isDebugEnabled()) {
            log.debug("重复检查入参：{}", duplicateOrderDTO);
        }
        return this.findCancelDuplicateOrder(duplicateOrderDTO);
    }

    /**
     * 下单重复工单判断   取消订单的下单时间点前、后7天内（含下单时间），有：
     （1）相同电话号码（3个电话有一个即算相同）
     （2）相同产品组
     （3）未被标记重复
     *
     * @param orderWork
     * @return
     */
    @Override
    public Long findDuplicateOrderId(OrderWork orderWork) {
        Assert.notNull(orderWork.getOrderId(), "工单ID不能为空");

        // 参数封装
        CancelDuplicateOrderDTO duplicateDTO = BeanMapper.map(orderWork, CancelDuplicateOrderDTO.class);
        OrderDetail orderDetail = orderDetailService.findOrderDetailByKey(orderWork.getOrderId());
        BeanMapper.copy(orderDetail, duplicateDTO);
        duplicateDTO.setServCategId(orderWork.getServCategId());
        duplicateDTO.setShowCategId(orderWork.getShowCategId());
        duplicateDTO.setExcludeOrderId(orderWork.getOrderId());

        return this.findCancelDuplicateOrder(duplicateDTO);
    }

    @Override
    public Long findDoingDuplicateOrderId(DoingDuplicateOrderDIO doingDuplicateOrderDIO) {
        try {
            // 查询在途重复单，组装查询条件
            BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery()
                    // 排除自己
                    .mustNot(QueryBuilders.termQuery("id", doingDuplicateOrderDIO.getWorkId()))
                    // 工单类型：新单
                    .filter(QueryBuilders.termQuery("type", OrderConsts.ORDER_TYPE_NEW))
                    // 工单结果：进行中
                    .filter(QueryBuilders.termQuery("resultStatus", OrderStatusConsts.WORK_RESULT_DOING))
                    // 联系电话
                    .filter(QueryBuilders.termsQuery("contact.phone", orderEncryptService.encrypt(doingDuplicateOrderDIO.getPhoneList())))
                    // 服务产品组ID
                    .filter(QueryBuilders.termQuery("servProductGroupId", doingDuplicateOrderDIO.getServProductGroupId()));

            // 排除行政子公司无法服务 或 行政服务商无法承接线索
            queryBuilder.mustNot(QueryBuilders.boolQuery()
                    .should(QueryBuilders.matchQuery("gridManageCompanyId", CompanyConsts.ZMN_JXJ_MANAGE_COMPANY_ID))
                    .should(QueryBuilders.matchQuery("gridManageCompanyId", CompanyConsts.ZMN_UNABLE_SERVICE_MANAGE_COMPANY_ID)));

            // 订单距离 <= 2KM
            queryBuilder.filter(QueryBuilders.geoDistanceQuery("contact.location")
                    .distance(2000, DistanceUnit.METERS)
                    .point(doingDuplicateOrderDIO.getLatitude(), doingDuplicateOrderDIO.getLongitude()));

            // 下单时间
            BoolQueryBuilder timeQuery = QueryBuilders.boolQuery();
            Date now = DateUtil.getNow();
            String startTime = DateUtil.toString(DateUtil.getDateStart(now));
            timeQuery.should(QueryBuilders.rangeQuery("receiveTime").gte(startTime));
            queryBuilder.filter(timeQuery);


            NativeSearchQueryBuilder nativeSearchQueryBuilder = new NativeSearchQueryBuilder();
            NativeSearchQuery build = nativeSearchQueryBuilder.withQuery(queryBuilder)
                    .withPageable(PageRequest.of(0, 1, Sort.by(Sort.Order.desc("receiveTime"))))
                    .build();
            if (log.isDebugEnabled()) {
                log.debug("workId={} 在途重复订单ES查询入参数：servProductGroupId={}  queryPhone={} longitude={} latitude={}", doingDuplicateOrderDIO.getWorkId(),
                        doingDuplicateOrderDIO.getServProductGroupId(), doingDuplicateOrderDIO.getPhoneList(),
                        doingDuplicateOrderDIO.getLongitude(), doingDuplicateOrderDIO.getLatitude());
            }
            FetchSourceFilter fetchSourceFilter = new FetchSourceFilter(new String[]{"id"}, new String[]{});
            build.addSourceFilter(fetchSourceFilter);
            List<EsOrderWork> page = orderWorkEsBService.listPageByQuery(build);
            if (log.isDebugEnabled()) {
                log.debug("在途重复订单查询 结果[{}]", JSON.toJSONString(page));
            }
            if (CollectionUtil.isNotNullOrEmpty(page)) {
                return page.get(0).getId();
            }
        } catch (Exception e) {
            log.error("findDoingDuplicateOrderId  orderId={} error [{}]", doingDuplicateOrderDIO.getWorkId(), e);
        }
        return null;
    }

    @Override
    public ResultDTO verifyCancelOrderDuplicate(Long orderId, Long workId, Long duplicateWorkId) {
        Objects.requireNonNull(orderId, "订单ID不能为空");
        Objects.requireNonNull(workId, "订单ID不能为空");
        Objects.requireNonNull(duplicateWorkId, "订单ID不能为空");
        // - 重复逻辑调整为：
        // -- a、重复源单不能是本工单；
        // -- b、同一下单平台，并订单业务类型相同，所有：新单-已完成，或新单-已取消的工单，下单时间2天内（示例：当天是2.5，包括：2.3，2.4日下单的）
        // -- c、电话1相同
        OrderWork work = orderWorkService.findOrderWorkByKey(orderId, workId);
        OrderWork originalWork = orderWorkService.findOrderWorkByKey(duplicateWorkId, duplicateWorkId);
        if (originalWork == null) {
            return ResultDTO.fail("重复原单号不存在");
        }
        if (Objects.equals(duplicateWorkId, workId)) {
            return ResultDTO.fail("重复原单号不能是本工单");
        }
        if (!Objects.equals(originalWork.getType(), OrderConsts.ORDER_TYPE_NEW)) {
            return ResultDTO.fail("重复原单不是新单");
        }
        if (!Objects.equals(work.getPlatWork(), originalWork.getPlatWork())) {
            return ResultDTO.fail("重复原单号不是同一服务平台");
        }

        if (!Objects.equals(work.getBizType(), originalWork.getBizType())) {
            return ResultDTO.fail("重复原单号业务类型不同");
        }

        OrderDetail orderDetail = orderDetailService.findOrderDetailByKey(orderId);
        OrderDetail originalOrderDetail = orderDetailService.findOrderDetailByKey(duplicateWorkId);
        List<String> phoneList = Lists.newArrayList(orderDetail.getTelephone());
        if (StringUtils.isNotBlank(orderDetail.getTelephone2())) {
            phoneList.add(orderDetail.getTelephone2());
        }
        if (StringUtils.isNotBlank(orderDetail.getTelephone3())) {
            phoneList.add(orderDetail.getTelephone3());
        }
        if (phoneList.contains(originalOrderDetail.getTelephone())
                || phoneList.contains(originalOrderDetail.getTelephone2())
                || phoneList.contains(originalOrderDetail.getTelephone3())) {
            return ResultDTO.success();
        }
        return ResultDTO.fail("源单与当前工单不匹配");
    }

    /**
     * 取消重复逻辑
     * @param duplicateDTO
     * @return
     */
    @Override
    public Long findCancelDuplicateOrder(CancelDuplicateOrderDTO duplicateDTO) {
        try {

            // 新单才查重复单
            if (!Objects.equals(duplicateDTO.getType(), OrderConsts.ORDER_TYPE_NEW)) {
                return null;
            }

            BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery()
                    .filter(QueryBuilders.termQuery("type", OrderConsts.ORDER_TYPE_NEW))
                    .filter(QueryBuilders.termQuery("isDuplicate", false))
                    .filter(QueryBuilders.termQuery("platWork", duplicateDTO.getPlatWork()));

            // 排除行政子公司无法服务 或 行政服务商无法承接线索
            queryBuilder.mustNot(QueryBuilders.boolQuery()
                    .should(QueryBuilders.matchQuery("gridManageCompanyId", CompanyConsts.ZMN_JXJ_MANAGE_COMPANY_ID))
                    .should(QueryBuilders.matchQuery("gridManageCompanyId", CompanyConsts.ZMN_UNABLE_SERVICE_MANAGE_COMPANY_ID)));

            Integer servProductGroupId = this.getServProductGroupId(duplicateDTO);
            // 房屋业务产品组 = C-防水补漏组/1000 || C-墙面组/1003 || C-瓷砖地板组/1005 || C-厨卫改造组/1031 || F-厨卫翻新/1032 || F-防水补漏组/1001 || F-墙面刷新组/1004
            boolean isHouse = houseServProductGroupIdList.contains(servProductGroupId);
            if (isHouse) {
                // 房屋业务线，匹配 服务分组判断
                queryBuilder.filter(QueryBuilders.termsQuery("servProductGroupId", houseServProductGroupIdList));
            } else if (furnitureServCategIdList.contains(duplicateDTO.getServCategId())) {
                // 家居类，判断服务分类
                queryBuilder.filter(QueryBuilders.termQuery("servCategId", duplicateDTO.getServCategId()));
            } else {
                // 其他，服务分类&&前台产品二级分类
                queryBuilder.filter(QueryBuilders.termQuery("servCategId", duplicateDTO.getServCategId()));
                queryBuilder.filter(QueryBuilders.termQuery("showCategTwoId", duplicateDTO.getShowCategId()));
            }

            // 下单时间点前/后， 房屋30天，其它7天
            int dayNum = isHouse ? 30 : 7;
            String startTime = DateUtil.toString(DateUtil.getDateStart(DateUtil.addDays(duplicateDTO.getReceiveTime(), -1 * dayNum)));
            String receiveTime = DateUtil.toString(duplicateDTO.getReceiveTime());
            String afterTime = DateUtil.toString(DateUtil.getDateStart(DateUtil.addDays(duplicateDTO.getReceiveTime(), dayNum)));

            BoolQueryBuilder timeQuery = QueryBuilders.boolQuery();
            timeQuery.should(QueryBuilders.rangeQuery("inputTime").gte(startTime).lte(receiveTime));
            timeQuery.should(QueryBuilders.rangeQuery("inputTime").gte(receiveTime).lte(afterTime));
            queryBuilder.filter(timeQuery);

            if (NumberUtil.isNotNullOrZero(duplicateDTO.getExcludeOrderId())) {
                queryBuilder.filter(QueryBuilders.boolQuery().mustNot(QueryBuilders.termQuery("id", duplicateDTO.getExcludeOrderId())));
                // queryBuilder.mustNot(QueryBuilders.termQuery("id", duplicateDTO.getExcludeOrderId()));
            }

            // 任一电话匹配
            List<String> phoneList = Lists.newArrayList(duplicateDTO.getTelephone());
            if (StringUtils.isNotBlank(duplicateDTO.getTelephone2())) {
                phoneList.add(duplicateDTO.getTelephone2());
            }
            if (StringUtils.isNotBlank(duplicateDTO.getTelephone3())) {
                phoneList.add(duplicateDTO.getTelephone3());
            }
            queryBuilder.filter(QueryBuilders.termsQuery("contact.phone", orderEncryptService.encrypt(phoneList)));

            NativeSearchQuery searchQuery = new NativeSearchQuery(queryBuilder);
            searchQuery.setPageable(PageRequest.of(0, 1, Sort.by(Sort.Order.desc("receiveTime"))));
            searchQuery.addSourceFilter(new FetchSourceFilter(new String[]{"id"}, new String[]{}));
            if (log.isDebugEnabled()) {
                log.debug("重复单查询[{}]", searchQuery.getQuery().toString());
            }
            List<EsOrderWork> page = orderWorkEsBService.listPageByQuery(searchQuery);
            if (log.isDebugEnabled()) {
                log.debug("重复单查询 结果[{}]", JSON.toJSONString(page));
            }

            if (CollectionUtil.isNotNullOrEmpty(page)) {
                return page.get(0).getId();
            }
        } catch (Exception ex) {
            log.info("重复单判断错误[{}]", ex, ex);
        }
        return null;
    }

    /**
     * 获取前台产品分组
     *
     * @param duplicateDTO
     * @return
     */
    private Integer getServProductGroupId(CancelDuplicateOrderDTO duplicateDTO) {
        if (NumberUtil.isNotNullOrZero(duplicateDTO.getServProductGroupId())) {
            return duplicateDTO.getServProductGroupId();
        }

        try {
            // 产品组ID
            CategProductGroupQuery categProductGroupQuery = new CategProductGroupQuery();
            categProductGroupQuery.setBizType(Optional.ofNullable(duplicateDTO.getBizType()).orElse(com.zmn.consts.GlobalConsts.BIZ_TYPE_C));
            categProductGroupQuery.setServCategId(duplicateDTO.getServCategId());
            categProductGroupQuery.setCategId(duplicateDTO.getShowCategId());
            categProductGroupQuery.setShowType(BaseProductConsts.EC_SHOW_TYPE);
            ResponseDTO<CategProductGroupDRO> categoryProductGroupDROResponseDTO = categServProductListRemoteService.getBasisProductGroupByQuery(categProductGroupQuery);
            CategProductGroupDRO categProductGroupDRO = categoryProductGroupDROResponseDTO.getData();
            if (Objects.nonNull(categProductGroupDRO)) {
                return categProductGroupDRO.getGroupId();
            }
        } catch (Exception e) {
            log.error("获取产品分组失败：{}", e);
        }
        return null;
    }

    @Override
    public Long findDistributeTimeoutDuplicateOrderId(OrderWork orderWork) {
        try {
            // 新单才查重复单
            if (!Objects.equals(orderWork.getType(), OrderConsts.ORDER_TYPE_NEW)) {
                return null;
            }

            String startTime = DateUtil.toString(DateUtil.getDateStart(DateUtil.addDays(orderWork.getReceiveTime(), -7)));
            String receiveTime = DateUtil.toString(orderWork.getReceiveTime());
            String afterTime = DateUtil.toString(DateUtil.getDateStart(DateUtil.addDays(orderWork.getReceiveTime(), 7)));

            BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery()
                    // 新单
                    .filter(QueryBuilders.termQuery("type", OrderConsts.ORDER_TYPE_NEW))
                    // 服务分组
                    .filter(QueryBuilders.termQuery("servProductGroupId", orderWork.getServProductGroupId()))
                    // 进行中
                    .filter(QueryBuilders.termQuery("resultStatus", OrderStatusConsts.WORK_RESULT_DOING))
                    // 状态
                    .filter(QueryBuilders.termsQuery("status", Lists.newArrayList(
                            OrderStatusConsts.WORK_STATUS_INPUT,
                            OrderStatusConsts.WORK_STATUS_CONFIRM,
                            OrderStatusConsts.WORK_STATUS_ASSIGN,
                            OrderStatusConsts.WORK_STATUS_DISTRIBUTE,
                            OrderStatusConsts.WORK_STATUS_TAKE)))
                    // 服务平台
                    .filter(QueryBuilders.termQuery("platWork", orderWork.getPlatWork()));

            // 排除自己
            queryBuilder.filter(QueryBuilders.boolQuery().mustNot(QueryBuilders.termQuery("id", orderWork.getWorkId())));

            OrderDetail orderDetail = orderDetailService.findOrderDetailByKey(orderWork.getOrderId());
            // 任一电话匹配
            List<String> phoneList = Lists.newArrayList(orderDetail.getTelephone());
            if (StringUtils.isNotBlank(orderDetail.getTelephone2())) {
                phoneList.add(orderDetail.getTelephone2());
            }
            if (StringUtils.isNotBlank(orderDetail.getTelephone3())) {
                phoneList.add(orderDetail.getTelephone3());
            }
            queryBuilder.filter(QueryBuilders.termsQuery("contact.queryPhone", phoneList));

            // 下单时间点前/后 7天
            BoolQueryBuilder timeQuery = QueryBuilders.boolQuery();
            timeQuery.should(QueryBuilders.rangeQuery("inputTime").gte(startTime).lte(receiveTime));
            timeQuery.should(QueryBuilders.rangeQuery("inputTime").gte(receiveTime).lte(afterTime));
            queryBuilder.filter(timeQuery);

            NativeSearchQuery searchQuery = new NativeSearchQuery(queryBuilder);
            searchQuery.setPageable(PageRequest.of(0, 1, Sort.by(Sort.Order.asc("receiveTime"))));
            FetchSourceFilter fetchSourceFilter = new FetchSourceFilter(new String[]{"id"}, new String[]{});
            searchQuery.addSourceFilter(fetchSourceFilter);
            log.debug("重复单查询[{}]", searchQuery.getQuery().toString());
            List<EsOrderWork> page = orderWorkEsBService.listPageByQuery(searchQuery);
            log.debug("重复单查询 结果[{}]", JSON.toJSONString(page));
            if (CollectionUtil.isNotNullOrEmpty(page)) {
                return page.get(0).getId();
            }
        } catch (Exception ex) {
            log.info("重复单判断错误[{}]", ex, ex);
        }

        return null;
    }

    /**
     * 疑似重复跟单处理
     *
     * @param duplicateOrderDTO
     */
    @Override
    public void handleSuspectedDuplicateTrack(DuplicateOrderDTO duplicateOrderDTO) {
        // 查询疑似重复订单
        Long duplicateOrderId = this.findDuplicateOrderId(duplicateOrderDTO);

        // 查询进行中的疑似重复跟单
        TrackWorkQuery query = new TrackWorkQuery();
        query.setOrderId(duplicateOrderDTO.getOrderId());
        query.setWorkId(duplicateOrderDTO.getOrderId());
        query.setNotStatus(TrackConsts.TRACK_STATUS_FINISHED);
        query.setTrackContentIdList(Lists.newArrayList(TrackConfigConsts.TRACK_CONTENT_ID_SUSPECTED_REPEATED));
        ResponseDTO<List<TrackWorkDRO>> listResponseDTO = trackWorkListRemoteService.listTrackByQuery(query);
        List<TrackWorkDRO> trackWorkDROList = listResponseDTO.getData();

        if (Objects.nonNull(duplicateOrderId)) {
            // 有进行中的疑似重复跟单，不处理
            if (CollectionUtils.isNotEmpty(trackWorkDROList)) {
                return;
            }

            // 没有进行中的疑似重复跟单，需要生成跟单
            TrackWorkDIO trackDIO = new TrackWorkDIO();
            trackDIO.setOrderId(duplicateOrderDTO.getOrderId());
            trackDIO.setWorkId(duplicateOrderDTO.getOrderId());
            trackDIO.setTrackContentId(TrackConfigConsts.TRACK_CONTENT_ID_SUSPECTED_REPEATED);
            trackDIO.setOperator(GlobalConsts.getOperatorTypeName(GlobalConsts.OPERATE_USER_TYPE_SYSTEM));
            trackDIO.setOperatorId((long) GlobalConsts.OPERATE_USER_TYPE_SYSTEM);
            trackDIO.setOperatorType(GlobalConsts.OPERATE_USER_TYPE_SYSTEM);
            ResponseDTO responseDTO = trackWorkModifyRemoteService.addTrack(trackDIO);
            log.info("修改订单&生成疑似跟单  orderId={} 出参={}", duplicateOrderDTO.getOrderId(), JSON.toJSONString(responseDTO));
            return;
        }

        // 不是重复单并且无进行中的疑似跟单，不处理
        if (CollectionUtil.isNullOrEmpty(trackWorkDROList)) {
            return;
        }

        // 不是重复单，有进行中的疑似重复跟单， 完结跟单
        TrackWorkDRO trackWorkDRO = trackWorkDROList.get(0);
        CompleteTrackDIO completeTrackDIO = BeanMapper.map(trackWorkDRO, CompleteTrackDIO.class);
        completeTrackDIO.setOperator(GlobalConsts.getOperatorTypeName(GlobalConsts.OPERATE_USER_TYPE_SYSTEM));
        completeTrackDIO.setOperatorId((long) GlobalConsts.OPERATE_USER_TYPE_SYSTEM);
        completeTrackDIO.setOperatorType(GlobalConsts.OPERATE_USER_TYPE_SYSTEM);
        ResponseDTO responseDTO = trackWorkModifyRemoteService.completeTrack(completeTrackDIO);
        log.info("修改订单&完结跟单 orderId={} 出参={}", trackWorkDRO.getOrderId(), JSON.toJSONString(responseDTO));
    }

    /**
     * 送到 疑似重复跟单处理 消息队列
     *
     * @param suspectedDuplicateOrderDTO
     */
    @Override
    public void noticeSuspectedDuplicateOrderToMq(SuspectedDuplicateOrderDTO suspectedDuplicateOrderDTO) {
        DuplicateOrderDTO duplicateOrderDTO = new DuplicateOrderDTO();
        BeanMapper.copy(suspectedDuplicateOrderDTO, duplicateOrderDTO);
        String key = String.format("tag-%s-%s", suspectedDuplicateOrderDTO.getOrderId(), DateUtil.getNowTimestamp());
        zmnMQSender.send(MqTopicConsts.ZMN_TOPIC_OMS, OmsMqTagConsts.SUSPECTED_DUPLICATE_ORDER, key, JSON.toJSONString(duplicateOrderDTO));
    }

    @Override
    public boolean verifyTelephoneOrProduct(VerifyTelephoneOrProductDTO verifyTelephoneOrProductDTO) {
        OrderWork orderWork = orderWorkService.findOrderWorkByKey(verifyTelephoneOrProductDTO.getOrderId(),
                verifyTelephoneOrProductDTO.getOrderId());
        OrderDetail orderDetail = orderDetailService.findOrderDetailByKey(verifyTelephoneOrProductDTO.getOrderId());

        boolean isTelephoneChanged = Objects.equals(verifyTelephoneOrProductDTO.getTelephone(), orderDetail.getTelephone());

        boolean isTelephone2Changed = Objects.equals(verifyTelephoneOrProductDTO.getTelephone2(), orderDetail.getTelephone2()) ||
                (StringUtil.isBlank(verifyTelephoneOrProductDTO.getTelephone2()) && StringUtil.isBlank(orderDetail.getTelephone2()));

        boolean isTelephone3Changed = Objects.equals(verifyTelephoneOrProductDTO.getTelephone3(), orderDetail.getTelephone3()) ||
                (StringUtil.isBlank(verifyTelephoneOrProductDTO.getTelephone3()) && StringUtil.isBlank(orderDetail.getTelephone3()));

        boolean isProductIdChanged = (Objects.equals(verifyTelephoneOrProductDTO.getProductShowType(), 1) &&
                Objects.equals(verifyTelephoneOrProductDTO.getProductId(), orderWork.getProductId())) ||
                (Objects.equals(verifyTelephoneOrProductDTO.getProductShowType(), 2) &&
                        Objects.equals(verifyTelephoneOrProductDTO.getProductId(), orderWork.getShowProductId()));

        if (isTelephoneChanged && isTelephone2Changed && isTelephone3Changed && isProductIdChanged) {
            return Boolean.FALSE;
        }
        return Boolean.TRUE;
    }
}